package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.article.mapper.ApArticleContentMapper;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.ApArticleService;
import com.heima.article.service.ArticleFreemarkerService;
import com.heima.common.constants.ArticleConstants;
import com.heima.file.service.FileStorageService;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.pojos.ApArticleContent;
import com.heima.model.search.vos.SearchArticleVo;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
@Transactional//待执行完的所有事务才提交
public class ArticleFreemarkerServiceImpl implements ArticleFreemarkerService {

    @Autowired//注入freeMakr的配置对象
    private Configuration configuration;

    @Autowired
    private FileStorageService fileStorageService;


    @Autowired
    private ApArticleMapper apArticleMapper;

    @Autowired
    private ApArticleService apArticleService;

    @Autowired
    private ApArticleContentMapper apArticleContentMapper;
    /**
     * 生成静态文件上传到MinIO中
     * @param apArticle 上传文件到minio的时候，要给文件命名要用文章的id
     * @param content 文章内容
     */
    @Async//表明为异步调用，在ApArticleServiceImpl里的saveArticle异步调用了(发布保存文章之后生成静态文件上传到MinIO中)
    //  然后在WemediaApplication里的main方法里加了@EnableAsync开启异步调用，在ApArticleServiceImpl的saveArticle方法里调用了
    @Override
    public void buildArticleToMinio(ApArticle apArticle, String content) {
        //1.获取文章内容，这里先不需要，因为content里已经有文章内容content了
//        ApArticleContent apArticleContent = apArticleContentMapper
//                .selectOne(Wrappers.<ApArticleContent>lambdaQuery().eq(ApArticleContent::getArticleId, 1383827787629252610L));
        if (StringUtils.isNotBlank(content)) {
            //2.文章内容通过freemarker生成html文件
            StringWriter out = new StringWriter();
            //找到模板
            Template template = null;
            try {
                template = configuration.getTemplate("article.ftl");
                Map<String, Object> contentDataModel = new HashMap<>();
                //往里面设置内容，content是模板中定义的变量名,是固定的
                //apArticleContent.getContent()获取的是数据库中的leadnews_article表里的content字段，是一个json对象，
                // 不能在模板中遍历，所以要转成json对象
                contentDataModel.put("content", JSONArray.parseArray(content));
                //合成，数据模型，输出流
                template.process(contentDataModel, out);
            } catch (Exception e) {
                e.printStackTrace();
            }

            //转换成一个inputStream
            InputStream in = new ByteArrayInputStream(out.toString().getBytes());

            //生成SearchArticleVo中的静态url private String staticUrl，才能发送消息创建索引
            //3.把html文件上传到minio中                     前缀             文件名称
            String path = fileStorageService
                    .uploadHtmlFile("", apArticle.getId() + ".html", in);
            //就是文件的访问路径
            //4.修改ap_article表，保存static_url字段

            //方法一：service
            apArticleService.update(Wrappers
                    .<ApArticle>lambdaUpdate()
                    .eq(ApArticle::getId, apArticle.getId())
                    .set(ApArticle::getStaticUrl, path));
            //方法二：mapper
//            ApArticle article = new ApArticle();
//            article.setId(apArticleContent.getArticleId());
//            article.setStaticUrl(path);
//            apArticleMapper.updateById(article);

            //WmNewsAutoScanServiceImpl里的autoScanWmNews就已经审核完成了
            //新增文章，审核完成后，发送消息通知搜索微服务端(消息消费者)，创建索引，添加数据到索引库
            createArticleESIndex(apArticle, content ,path);
            //因为article里并不包含静态url和内容，但是SearchArticleVo里包含
                  //静态url
            //    private String staticUrl;
                  //文章内容
            //    private String content;
            // 所以要传path和content


        }
    }

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    /**
     * 新增文章，审核完成后，上传文章到minio后，发送消息通知搜索微服务端(消息消费者)，创建索引，添加数据到索引库
     * @param apArticle
     * @param content
     */
    private void createArticleESIndex(ApArticle apArticle, String content, String path) {

        SearchArticleVo searchArticleVo = new SearchArticleVo();
        BeanUtils.copyProperties(apArticle, searchArticleVo);

        searchArticleVo.setContent(content);
        searchArticleVo.setStaticUrl(path);

        //审核完文章之后，发送消息，通知搜索微服务端，创建索引，添加数据到索引库(需要在nacos中配置生产者的内容)
        System.out.println("审核完文章之后，发送消息，通知搜索微服务端，创建索引，添加数据到索引库(需要在nacos中配置生产者的内容)");
        kafkaTemplate.send(ArticleConstants.ARTICLE_ES_SYNC_TOPIC, JSON.toJSONString(searchArticleVo));

        //消息生产者，发送消息，消息消费者，接收消息，消费消息，消费完消息，删除消息，消息持久化
        //消息生产者，发送消息，消息消费者，接收消息，消费消息，消费完消息，删除消息，消息持久化
    }
}
